home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programmer Power Tools
/
Programmer Power Tools.iso
/
screen
/
hprtsc.arc
/
HPRTSC.ASM
next >
Wrap
Assembly Source File
|
1987-08-19
|
11KB
|
374 lines
PAGE ,132
TITLE HPRTSC
SUBTTL Description
; Copyright (c) 1987, Background Processes
;
; Permission is hereby granted to copy, distribute, modify, include,
; burn, rape, or pillage this software in accordance with the following
; guidelines:
;
; 1) Distribution of this program is to be free. If a charge is made
; for copying, it must be no more than $5 US. Permission for
; inclusion into commercial products must be obtained individually.
;
; 2) Distribution of the program must include this complete source
; code, or at least it should be made available. Software
; exchange should not only be a way of getting free software,
; but should also be a learning experience. The best way to
; learn is to be able to read the source code.
;
; 3) You promise not to laugh at the code (at least not too hard). I'm
; a PDP-11 programmer. If that doesn't mean anything to you, ask
; a hacker friend about the advantages of orthogonal instruction sets
; and REAL general registers.
;
; 4) If you find (or correct - hint, hint) any bugs in this program, I
; would appreciate it if you would let me know. This way I can
; learn, too.
;
; Alan Groupe
; Background Processes
; PO Box 6347
; Nashua, NH 03063-6347
; This program implements a graphics screen dump from a Hercules
; monochrome graphics board. It is similar to the DOS GRAPHICS.COM in
; that it takes over the PrtSc interrupt.
; When HPRTSC is typed at the DOS prompt, it grabs the PrtSc interrupt
; vector, and then issues a terminate and stay resident DOS function
; call. When the PrtSc key is pressed, this program checks the Hercules
; board to determine whether it is in text or graphics mode. If the
; board is in text mode, the program simply executes a far jump to the
; original PrtSc routine. If the board is in graphics mode, the program
; waits for a key to be pressed on the keyboard. If the '1' key is pressed,
; the program scans through the first graphics page (B0000 - B7FFF; called
; page 0 in the Hercules manual) and formats it for output on the printer.
; If the '2' key is pressed, the second graphics page (B8000 - BFFFF) is
; printed. If any other key is pressed, you will hear a short beep and HPRTSC
; will just return. You can use this to freeze an animated graphics display
; to look at it more closely. Just press PrtSc to freeze the screen. To
; unfreeze it, just press any key other than '1' or '2'.
;
; The dot mapping of a Hercules board is a little weird. Each byte in
; the graphics memory corresponds to eight dots horizontally, with the
; most significant bit of each byte representing the leftmost dot of the
; eight. There are 720 dots across on the display, so the first 90 bytes
; (B0000 - B005A) make up the first line on the screen (line 1).
; However, the next 90 bytes are not line 2, but rather line 5. The next
; 90 bytes, line 9. This continues down the screen until line 345
; (B1E3C). The remaining 170 bytes (B1E96 - B1FFF) are unused. Then the
; 90 byte groups starting at B2000 correspond to lines 2, 6, 10, etc.
; Therefore, lines 1-10 have the respective starting addresses B0000,
; B2000, B4000, B6000, B005A, B205A, B405A, B605A, B00B4, and B20B4.
;
; This, of course, is not even close to how an Epson printer maps dots
; on the paper. The Epson printer takes an eight bit byte and prints a
; column of 8 dots vertically, with the most significant bit at the top.
;
; Since the Hercules board is organized horizontally and the Epson printer
; is organized vertically, this program prints the screen image rotated 90
; degrees.
SUBTTL Entry Point
PAGE +
cseg segment
assume cs:cseg,ds:cseg
; This is the initial program entry point. It jumps to 'init' which sets
; up the interrupt vector, prints out a message confirming program load,
; and does a terminate and stay resident call.
jmp init ; jump around real code to load in memory
SUBTTL PrtSc Entry Point
PAGE +
; This is the entry point when PrtSc is pressed. It is ORG'ed at location
; 348 (minus 100h) to allow the previous 348 bytes, including the now
; unnecessary PSP to be used as a buffer to hold a full vertical scan of the
; screen.
org 348-100h
int5:
push ax
push bx
push dx
; First we must determine whether the Hercules board is in text mode or
; graphics mode. This is done with a program given to me by Hercules Computer
; Technology Inc. It isn't real clear to me why this program works the way it
; does, but it appears that if you force trip the light pen, it returns the
; character location (6845 meaning) just past the end of the screen. This may
; have something to do with the fact that there is no light pen receiving a
; raster pulse. If this is the case, I have no idea if this still works if you
; actually have a light pen connected.
ourstat equ 03bah
notvsync equ 80h
lpreset equ 03bbh
lpset equ 03b9h
our6845 equ 03b4h
threshold equ (80*25 + 45*87)/2
mov dx,ourstat
w1: in al,dx ; first, wait for vertical retrace
test al,notvsync
jz w1
w2: in al,dx ; then make sure not to test during vertical
test al,notvsync ; retrace
jnz w2
xor al,al ; tickle light pen
mov dx,lpreset
out dx,al
mov dx,lpset
out dx,al
mov al,16 ; get high byte of lp trip offset
mov dx,our6845
out dx,al
inc dx
in al,dx
mov bh,al
mov al,17 ; and low byte
mov dx,our6845
out dx,al
inc dx
in al,dx
mov ah,bh ; return light pen trip address
cmp ax,threshold
pop dx ; restore original user registers
pop bx
pop ax
ja gprint ; above threshold, in graphics mode
; The following two lines are a 'jmp far' instruction to jump to the BIOS
; print screen routine if the Hercules board is in text mode. The location
; is filled in in the 'init' routine.
tjump: db 0eah ;! JMP FAR 0:0
dw 0,0
SUBTTL Graphics Entry Point
PAGE +
; This is the entry point if the Hercules board is in graphics mode.
gprint:
push ax ; save all registers
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
; First test location 50:0 to see if print screen is already in progress.
mov ax,50h
mov ds,ax
cmp byte ptr ds:0,1 ; prtsc already active?
mov byte ptr ds:0,1 ; it is now
mov ax,cs ; retore ds:
mov ds,ax
jnz gp1 ; print screen in progress before? no.
jmp exit ; yes
gp1:
xor ax,ax ; set for read char
int 16h ; read char from keyboard
mov dx,0b000h ; assume page 1
cmp al,'1'
je gp3
mov dx,0b800h ; page 2
cmp al,'2'
je gp3
;
; neither '1' nor '2', so beep an error and return
;
timer equ 40h
port_b equ 61h
mov al,10110110b ; sel tim 2,lsb,msb,binary
out timer+3,al ; write the timer mode reg
mov ax,533h ; divisor for 1000 hz
out timer+2,al ; write timer 2 cnt - lsb
mov al,ah
out timer+2,al ; write timer 2 cnt - msb
in al,port_b ; get current setting of port
mov ah,al ; save that setting
or al,03 ; turn speaker on
out port_b,al
sub cx,cx ; set count to 500 ms
gp2: loop gp2 ; delay before turning off
mov al,ah ; recover value of port
out port_b,al
jmp done
;
; set up printer for graphics printing
;
gp3: mov ds,dx ; segment address of page requested
push cs ; es points to work area which is at
pop es ; beginning of code segment
xor dx,dx ; printer number is zero (LPT1)
xor si,si ; horizontal offset (start at left edge)
mov ax,27 ; select 8/72" line feeds (ESC A 8)
int 17h
mov ax,'A'
int 17h
mov ax,8
int 17h
mov ax,27 ; set selection in force (ESC 2)
int 17h
mov ax,'2'
int 17h
; start running through screen starting with lower left corner, working up
; and then to the right
;
; l1 is loop for each vertical pass. This is also one print line.
l1: mov bx,1e3ch ; bottom-most scan line in first quadrant
mov cx,87 ; # horizontal lines in a quadrant (348/4)
xor di,di ; pointer into ES: work area (beginning of code)
l2: mov al,6000h[bx+si] ; get character from quadrant 4 scan line
stosb ; and store in work area
cmp al,0 ; if it was other than a zero, store new
je $+4 ; of di in dx so dx will be length of line to
mov dx,di ; print (null truncated)
mov al,4000h[bx+si] ; do likewise for third quadrant
stosb
cmp al,0
je $+4
mov dx,di
mov al,2000h[bx+si] ; and second
stosb
cmp al,0
je $+4
mov dx,di
mov al,[bx+si] ; and the first quadrant
stosb
cmp al,0
je $+4
mov dx,di
sub bx,5ah ; up one horizontal scan line (90 bytes)
loop l2 ; (effectively 4 horizontal scan lines)
cmp dx,0 ; completely blank vertical line?
je l5 ; don't print, just advance paper
push dx ; save length of line to print
xor dx,dx ; for printer zero, again
mov cx,10 ; count for left margin (ie, 10 spaces)
l3: mov ax,' ' ; the print them
int 17h
loop l3
mov ax,27 ; then print the graphics line
int 17h
mov ax,'L' ; ESC L introduction (double density)
int 17h
pop cx ; length of line to print
shl cx,1 ; *2 since we print double for double density
mov ax,cx
xor ah,ah ; get least significant byte
int 17h ; and send it
xor ah,ah
mov al,ch ; then get most significant byte
int 17h ; and send it
shr cx,1 ; then shift back down to real count
push si ; save horizontal offset
xor si,si ; point to save graphics line
l4: lods byte ptr cs:0 ; get a character to print
xor ah,ah
push ax ; BUG: my clone BIOS' int 17 stomps on AL
int 17h ; and print it
pop ax ; restore due to my BIOS' bug
int 17h ; print a second time for increased density
loop l4 ; till end of line
pop si ; and restore horizontal offset for next pass
l5: mov ax,0dh ; now do a CRLF
int 17h
mov ax,0ah
int 17h
inc si ; move one space to the right
cmp si,5ah ; already on right hand edge?
jae l6 ; yes
jmp l1 ; no, do another vertical pass
l6:
mov ax,27 ; set the printer back to 6lpi
int 17h ; (even if it was at 8lpi)
mov ax,'2'
int 17h
mov ax,12 ; really 12/72 of an inch
int 17h
done: mov ax,50h
mov ds,ax
mov byte ptr ds:0,0 ; prtsc is now over
exit:
pop es ; restore all registers
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
iret ; and return to what user was doing
SUBTTL Initial Entry Point (Setup)
PAGE +
; This is the code executed the first time the program is invoked. It first
; builds a jump instruction at location 'tjump' that jumps to the BIOS print
; screen routine when the Hercules board is in text mode. Then it loads the
; print screen vector to point to the entry point and issues a terminate and
; stay resident call.
init:
mov ax,ds:2ch
mov es,ax ; segment address of environment strings
mov ah,49h ; deallocate our copy of environment strings
int 21h
mov ax,3505h ; get address for normal print screen
int 21h
mov ax,es
mov word ptr tjump+103h,ax ; store segment address in jmp instr.
mov word ptr tjump+101h,bx ; likewise with offset
mov dx,offset int5+100h
mov ax,2505h ; grab print screen interrupt vector
int 21h
mov dx,offset announce+100h
mov ah,09h ; print announcement
int 21h
mov dx,offset init+100h ; lock program in memory
int 27h
announce:
db 0dh,0ah,'HPrtSc - Graphics Screen Dump, Version 1.00',0dh,0ah
db 'Copyright (c) 1987, Background Processes',0dh,0ah,'$'
cseg ends
end